package main

import (
	"fmt"
	_ "image/png" // 支持PNG格式
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"github.com/getlantern/systray"

	"uselesscapslock/config"
	"uselesscapslock/platform"
	"uselesscapslock/web"
)

var fyneApp fyne.App
var webServer *web.Server

// 添加版本信息到编译参数
var (
	version   = "dev"
	commit    = "none"
	buildDate = "unknown"
)

func main() {
	// 记录版本信息
	log.Printf("Version: %s, Commit: %s, BuildDate: %s\n", version, commit, buildDate)

	// 设置日志输出到文件
	logFile, err := setupLogging()
	if err != nil {
		log.Printf("设置日志文件失败: %v\n", err)
		os.Exit(1)
	}
	defer logFile.Close()

	// 添加 panic 恢复
	defer func() {
		if r := recover(); r != nil {
			log.Printf("程序发生严重错误: %v\n", r)
			// 确保在 panic 时也能正常清理资源
			cleanup()
			os.Exit(1)
		}
	}()

	// 获取可执行文件所在目录
	exePath, err := os.Executable()
	if err != nil {
		log.Printf("获取程序路径失败: %v\n", err)
		os.Exit(1)
	}
	exeDir := filepath.Dir(exePath)

	// 切换工作目录到可执行文件所在目录
	if err := os.Chdir(exeDir); err != nil {
		log.Printf("切换工作目录失败: %v\n", err)
		os.Exit(1)
	}

	// 初始化配置路径
	config.InitConfig(exeDir)

	// 添加管理员权限检查和提权
	if err := platform.RunAsAdmin(); err != nil {
		log.Printf("提权失败: %v\n", err)
		os.Exit(1)
	}

	// 加载配置
	cfg, err := config.LoadConfig()
	if err != nil {
		log.Printf("加载配置失败: %v\n", err)
		cfg = &config.Config{}
	}

	// 创建Fyne应用
	fyneApp = app.New()

	// 初始化键盘管理器
	keyboardManager := platform.GetKeyboardManager()
	if err := keyboardManager.Start(); err != nil {
		log.Printf("启动键盘管理器失败: %v\n", err)
	}

	// 启动系统托盘
	log.Println("启动系统托盘...")
	go systray.Run(onReady, onExit)

	// 如果配置了自动打开配置界面
	if cfg.Settings.AutoOpenConfig {
		go func() {
			// 等待一小段时间确保系统托盘已经准备就绪
			time.Sleep(500 * time.Millisecond)
			showConfig()
		}()
	}

	// 运行Fyne应用
	fyneApp.Run()
}

// getIcon 返回托盘图标的二进制数据
func getIcon() []byte {
	exePath, err := os.Executable()
	if err != nil {
		log.Printf("获取程序路径失败: %v\n", err)
		return getDefaultIcon()
	}

	// 直接使用 ICO 格式的图标文件
	iconPath := filepath.Join(filepath.Dir(exePath), "icon.ico")
	iconData, err := os.ReadFile(iconPath)
	if err != nil {
		log.Printf("读取图标文件失败: %v\n", err)
		return getDefaultIcon()
	}
	return iconData
}

func getDefaultIcon() []byte {
	// 返回默认图标数据
	return []byte{
		0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00,
		0x18, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
		0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
		0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
}

func showConfig() {
	log.Println("显示配置窗口...")

	// 确保 web 服务器只启动一次
	if webServer == nil {
		webServer = web.NewServer(8080)
		go func() {
			if err := webServer.Start(); err != nil {
				if !strings.Contains(err.Error(), "address already in use") {
					log.Printf("启动web服务器失败: %v\n", err)
				}
			}
		}()
		// 等待服务器启动
		time.Sleep(100 * time.Millisecond)
	}

	// 打开默认浏览器
	url := "http://localhost:8080"
	if err := platform.OpenBrowser(url); err != nil {
		log.Printf("打开浏览器失败: %v\n", err)
	}
}

func onReady() {
	log.Println("系统托盘准备就绪")
	// 添加短暂延时
	time.Sleep(100 * time.Millisecond)

	// 设置托盘图标和提示
	icon := getIcon()
	log.Printf("设置托盘图标，大小: %d bytes\n", len(icon))
	systray.SetIcon(icon)
	systray.SetTooltip("UselessCapsLock - 按键映射工具")

	// 添加菜单项
	log.Println("添加托盘菜单项...")
	mConfig := systray.AddMenuItem("配置", "打开配置界面")
	mQuit := systray.AddMenuItem("退出", "退出程序")
	log.Println("托盘菜单项添加完成")

	go func() {
		log.Println("开始监听托盘菜单事件...")
		for {
			select {
			case <-mConfig.ClickedCh:
				log.Println("点击托盘配置菜单")
				showConfig()
			case <-mQuit.ClickedCh:
				log.Println("点击托盘退出菜单")
				cleanup() // 确保调用 cleanup
				fyneApp.Quit()
				systray.Quit()
				return
			}
		}
	}()

	log.Println("托盘初始化完成")
}

func onExit() {
	log.Println("程序退出...")
	platform.GetKeyboardManager().Stop()
}

func setupLogging() (*os.File, error) {
	// 获取可执行文件所在目录
	exePath, err := os.Executable()
	if err != nil {
		return nil, fmt.Errorf("获取程序路径失败: %v", err)
	}
	exeDir := filepath.Dir(exePath)

	// 创建日志文件
	logPath := filepath.Join(exeDir, "app.log")
	logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("创建日志文件失败: %v", err)
	}

	// 设置日志输出到文件和控制台
	mw := io.MultiWriter(os.Stdout, logFile)
	log.SetOutput(mw)

	// 添加时间戳到日志
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	return logFile, nil
}

// 清理资源的函数
func cleanup() {
	log.Println("开始清理资源...")

	// 停止键盘管理器
	log.Println("停止键盘管理器...")
	platform.GetKeyboardManager().Stop()

	// 停止 web 服务器
	if webServer != nil {
		log.Println("停止web服务器...")
		if err := webServer.Stop(); err != nil {
			log.Printf("停止web服务器失败: %v\n", err)
		}
	}

	// 退出系统托盘
	log.Println("退出系统托盘...")
	systray.Quit()

	// 退出 Fyne 应用
	if fyneApp != nil {
		log.Println("退出Fyne应用...")
		fyneApp.Quit()
	}

	log.Println("程序清理完成，正在退出...")
}
